package net.sf.ivyide.idea;

import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.ModifiableModuleModel;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.roots.ModuleCircularDependencyException;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.libraries.LibraryTable;

import java.io.File;
import java.util.*;

public class UpdateModules
        implements ProgressAwareRunnable {

    private static final Logger LOGGER = Logger.getInstance(UpdateModules.class.getName());

    private Project m_project;
    private IvyProjectSettings m_settings;
    private static final String GENERATE_BY_IVY = "generate.by.ivy";


    public UpdateModules(final IvyProjectSettings settings, Project project) {

        m_settings = settings;
        m_project = project;
    }

    public void run(ProgressIndicator progressIndicator) {
        try {
            List<ResolvedModule> resolvedModules = new ModuleResolver().getResolvedModules(m_settings, progressIndicator);

            //ModuleManager instance = ModuleManager.getInstance(m_project);
            //final ModifiableModuleModel modulesModel = instance.getModifiableModel();

            final ModifiableModuleModel modulesModel = ProgressUtilities.executeAsReadAction(new ProgressAwareCallable<ModifiableModuleModel>() {
                public ModifiableModuleModel call(ProgressIndicator progressIndicator) throws Exception {
                    ModuleManager instance = ModuleManager.getInstance(m_project);
                    return instance.getModifiableModel();
                }
            }, progressIndicator);
            final String projectDir = m_project.getBaseDir().getPath();

            final LibraryTable projectLibraryTable = m_project.getComponent(LibraryTable.class);
            final Map<String, Library> projectLibrariesUsedByAnyModule = new HashMap<String, Library>();

            double maxResolves = resolvedModules.size();
            double syncedCount = 0;
            progressIndicator.setIndeterminate(false);
            progressIndicator.setFraction(0.1);
            final Set<Module> usedModules = new HashSet<Module>();
            LOGGER.info("Starting sunc");
            for (final ResolvedModule resolvedModule : resolvedModules) {
                //m_indicator.pushState();
                //  try {
                final String modulePath = new File(projectDir, "ivymodules/" + resolvedModule.getModuleId().getName() + ".iml").getPath();
                //IvyDependenciesStep.<Void>executeRunnableWithProgress(m_component, "Synchronizing module " + resolvedModule.getModuleId().getName(), "Oeps", new Callable() {
                //    public Object call() throws Exception {
                //indicator.setText("pinh " + resolvedModule.getModuleId().getName());
                //IvyProjectComponent.runWriteActionInSwingThread(new Runnable() {
                //   public void run() {

                //must be executed on swing thread (ModifiableModuleModel#newModule creates a write action)  
                final ModifiableRootModel modifiableModel = ProgressUtilities.executeAsWriteActionOnEventQueue(new ProgressAwareCallable<ModifiableRootModel>() {
                    public ModifiableRootModel call(ProgressIndicator progressIndicator) throws Exception {
                        Module moduleByPath = modulesModel.newModule(modulePath);
                        moduleByPath.setOption(GENERATE_BY_IVY, "true");
                        usedModules.add(moduleByPath);
                        moduleByPath.setSavePathsRelative(true);
                        final ModifiableRootModel modifiableModel = ModuleRootManager.getInstance(moduleByPath).getModifiableModel();
                        //setup root model
                        LOGGER.info("modifiableModel = " + modifiableModel);
                        LOGGER.info("modifiableModel.getModule().getName() = " + modifiableModel.getModule().getName());
                        modifiableModel.inheritJdk();
                        return modifiableModel;
                    }
                }, progressIndicator);
                final UpdateModule updateModule = new UpdateModule(m_settings.m_environmentInfo, resolvedModule, modifiableModel, projectLibraryTable, projectLibrariesUsedByAnyModule);
                updateModule.run(progressIndicator);
                ProgressUtilities.executeAsWriteActionOnEventQueue(new ProgressAwareRunnable() {
                    public void run(ProgressIndicator progressIndicator) {
                        modifiableModel.commit();
                    }
                }, progressIndicator);
                double fraction = ++syncedCount / maxResolves;
                progressIndicator.setFraction(fraction);
            }
            progressIndicator.setIndeterminate(true);
            LOGGER.info("Cleaning ");
            progressIndicator.setText("Cleaning unused modules");
            ProgressUtilities.executeAsReadAction(new ProgressAwareCallable<Void>() {
                public Void call(ProgressIndicator progressIndicator) throws Exception {
                    for (Module module : modulesModel.getModules()) {
                        if (!usedModules.contains(module)) {
                            if ("true".equals(module.getOptionValue(GENERATE_BY_IVY))) {
                                modulesModel.disposeModule(module);
                            }
                        }
                    }
                    return null;
                }
            }, progressIndicator);
            progressIndicator.setText("Finalizing project...");
            ProgressUtilities.executeAsWriteActionOnEventQueue(new ProgressAwareRunnable() {
                public void run(ProgressIndicator progressIndicator) {
                    UpdateModule.cleanUnusedLibraries(projectLibrariesUsedByAnyModule.values(), projectLibraryTable);
                    try {
                        modulesModel.commit();
                    }

                    catch (ModuleCircularDependencyException e) {
                        throw new RuntimeException(e);
                    }
                    //To change body of implemented methods use File | Settings | File Templates.
                }
            }, progressIndicator);
            LOGGER.info("Done");
        }

        catch (
                Exception e
                )

        {
            throw new RuntimeException(e);
        }
    }

}
